package com.sia.springcloud.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ctc.wstx.shaded.msv_core.reader.relax.core.ModuleState;
import com.mysql.cj.protocol.Protocol;
import com.sia.springcloud.mapper.DeviceMapper;
import com.sia.springcloud.mapper.PointMapper;
import com.sia.springcloud.model.Device;
import com.sia.springcloud.model.Point;
import com.sia.springcloud.result.GridDataResult;
import com.sia.springcloud.service.ICollectService;
import com.sia.springcloud.result.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: Sirius
 * @Date: 2021/12/27 17:30
 * @Description: 数采接口实现类
 **/
@Slf4j
@Service
public class CollectService implements ICollectService {


    @Resource
    private ProtocolService protocolService;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private DeviceMapper deviceMapper;

    @Resource
    private PointMapper pointMapper;

    //定义锁对象
    private final ReentrantLock lock = new ReentrantLock();


    /**
     * 开启指定设备的数采
     * <p>
     * 注意：core中不需要传来protocolName，当调用其他的协议微服务的时候是否需要还需要商定
     * 但是其他协议微服务的controller应该实现一个interface，而core则不需要
     * <p>
     * 如果这个设备下面没有点位怎么办，还开启数采吗，还是说直接返回相关信息
     *
     * @param deviceId
     * @return
     */
    @Override
    public String startCollect(Integer deviceId) {
        log.info("开启数采：" + deviceId);

        String protocolName;
        Device device;
        try {

            device = deviceMapper.selectById(deviceId);
            protocolName = device.getProtocolName();

            device = deviceMapper.selectById(deviceId);
            if (null == device) {
                log.warn("设备 {} 在数据库中未查询到", deviceId);

                return ResultUtil.createSimpleFailureJson("设备不存在");
            } else {
                QueryWrapper<Point> pointQueryWrapper = new QueryWrapper<>();
                pointQueryWrapper.eq("device_id", deviceId);
                List<Point> pointList = pointMapper.selectList(pointQueryWrapper);

                if (pointList.size() <= 0) {
                    log.warn("设备 {} 没有添加点位信息", deviceId);

                    return ResultUtil.createSimpleFailureJson("该设备没有点位信息");
                }

            }

        } catch (Exception e) {
            log.error("设备 {} 在数据库中查询的过程中发生异常", deviceId);
            log.error(e.getMessage());

            return ResultUtil.createSimpleFailureJson("查询数据库的过程中发生异常");
        }


        try {
            String instanceId = protocolService.getInstanceIdByProtocolName(protocolName);


            //分发开启数采请求，并解析返回信息
            String priorityUrl = "http://" + instanceId + "/collectController/startCollect";
            MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
            parameters.add("deviceId", String.valueOf(deviceId));
            String startCollectResult = restTemplate.postForObject(priorityUrl, parameters, String.class);
            JSONObject jsonObject = JSONObject.parseObject(startCollectResult);
            String result = jsonObject.getString("result");


            if ("Y".equals(result)) {
                device.setCollect(1);
                deviceMapper.updateById(device);
                return ResultUtil.createSimpleSuccessJson("设备启动成功");
            } else {
                device.setCollect(0);
                deviceMapper.updateById(device);
                return ResultUtil.createSimpleFailureJson("设备启动失败");
            }
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return ResultUtil.createSimpleFailureJson("启动失败，请检查后重试");

    }


    /**
     * 关闭指定设备的数采
     *
     * @param deviceId
     * @return 如果返回ture，已经走完了关闭数采的流程，尽力关闭了
     * 如果返回false，说明关闭数采的过程中发生了异常：没有该设备对应的协议，或者发生异常
     */
    @Override
    public String stopCollect(Integer deviceId) {
        log.info("关闭数采" + deviceId);

        Device device = deviceMapper.selectById(deviceId);

        if (null == device) {
            log.warn("设备 {} 在数据库中未查询到", deviceId);
            return ResultUtil.createSimpleFailureJson("数据库中查询为空");
        }
        //即使改设备没有点位，也可以尝试停止数采，没有点位情况下是返回1


        try {
            String protocolName = device.getProtocolName();

            String instanceId = protocolService.getInstanceIdByProtocolName(protocolName);

            //分发停止数采请求，并解析返回的消息
            String url = "http://" + instanceId + "/collectController/stopCollect";
            MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
            parameters.add("deviceId", String.valueOf(deviceId));
            String stopCollectResult = restTemplate.postForObject(url, parameters, String.class);
            JSONObject jsonObject = JSONObject.parseObject(stopCollectResult);
            String result = jsonObject.getString("result");

            //根据是否成功删除来判断是否更新信息
            if ("Y".equals(result)) {
                log.info("说明已经删除，可以修改数采状态");
                log.info("说明有可能该微服务已经停止，应该强制停止数采");
                device.setCollect(0);
                device.setMicroservice("nothing");
                deviceMapper.updateById(device);
                return ResultUtil.createSimpleSuccessJson("数采关闭成功");
            }
        } catch (Exception e) {
            log.error("停止数采过程中发生异常");
            log.error(e.getMessage());
        }
        //为什么不需要强制停止数采：
        // 如果处于数采状态，但是其微服务已经停止就会触发心跳保护，要么停止数采，要么转移到其他微服务上
        // 如果处于数采状态，并且其微服务没有停止，那么就会正常停止

        return ResultUtil.createSimpleFailureJson("数采关闭失败");
    }


    /**
     * 接收协议微服务发送的心跳信息
     *
     * @param heartbeatId
     * @param instanceId
     * @param protocolName
     * @param deviceNum
     * @param time
     * @return 没有返回值
     */
    @Override
    public void heartbeat(String heartbeatId, String instanceId, String protocolName, String deviceNum, String time) {

    }


    /**
     * 开启或关闭心跳保护
     * <p>
     * 两个作用：
     * 1.如果是正常情况下开启的，能够进行心跳保护
     * 2.如果是因为异常关机后服务正常后开启的，具有一键重连的作用（也就是自动重启的作用）
     *
     * @return 返回是否开启成功
     */
    @Override
    public String heartbeatProtect(boolean protect) {
        log.info("设置心跳");
        if (protect) {
            return ResultUtil.createSimpleFailureJson("无法开启心跳保护");
        } else {
            return ResultUtil.createSimpleFailureJson("无法开启心跳保护");
        }
    }


    /**
     * 获取心跳保护的状态
     *
     * @return 心跳保护处于开启返回1，否则返回0
     */
    @Override
    public String heartbeatProtectStatus() {
        log.info("获取心跳保护状态");
        return ResultUtil.createSimpleSuccessJson("0");
    }

    /**
     * 获取正在运行的数采协议微服务的种类
     *
     * @return
     */
    @Override
    public String protocolList() {
        log.info("获取数采协议微服务列表");


        return protocolService.getProtocolList();
    }


    /**
     * 获取指定设备数采状态
     *
     * @return 如果开启数采返回1，关闭返回0
     */
    @Override
    public String deviceStatus(String deviceId) {
        log.info("获取执行设备数采状态" + deviceId);

        Device device = deviceMapper.selectById(deviceId);
        if (device.getCollect().equals(1)) {
            return ResultUtil.createSimpleSuccessJson("1");
        } else {
            return ResultUtil.createSimpleSuccessJson("0");
        }
    }


    /**
     * 写变量方法
     *
     * @param deviceId
     * @param value
     * @return
     */
    @Override
    public String writeVariable(String deviceId, String value) {
        return null;
    }


}
